﻿using Microsoft.CSharp.Activities;
using System;
using System.Activities;
using System.Activities.Validation;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Markup;
using WFExtended.Activities;
using WFExtended.Framework.Constraints;
using WFExtended.Framework.ServiceModel;
using WFExtended.Twitter.Activities.Designers;

namespace WFExtended.Twitter.Activities
{
    /// <summary>
    /// Twitter Proxy Activity
    /// </summary>
    [ToolboxBitmapAttribute(typeof(EntryPoint), "Resources.TwitterProxyToolbox.bmp")]
    [Designer(typeof(TwitterProxyDesigner))]
    [ContentProperty("Body")]
    [Description("Twitter Proxy")]
    public class TwitterProxy : AWcfProxyActivity<ITwitterApi>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="TwitterProxy"/> class.
        /// </summary>
        public TwitterProxy()
            : base("twitterProxy", GetDefaultConstraints())
        {
            UseSsl = true;
            EnableRateLimitAutoRetry = true;
            RateLimitAutoRetryDelay = new InArgument<TimeSpan>(new CSharpValue<TimeSpan>("new TimeSpan(0,2,0)"));
        }

        private static Constraint[] GetDefaultConstraints()
        {
            return new Constraint[]
            {
                 new ContainConstraint<TwitterProxy>(true, "Operation", typeof(ITwitterOperationActivity)).GetConstraint(),
            };
        }


        public RuntimeArgument Arg;

        #region Base Proxy Properties

        /// <summary>
        /// Get or Set the type of the Channel
        /// </summary>
        [Browsable(false)]
        public override ChannelType ChannelType { get; set; }

        /// <summary>
        /// Get or Set if the persistence enabled
        /// </summary>
        [Browsable(false)]
        public override bool EnablePersistence { get; set; }

        /// <summary>
        /// Get or Set the number of retry for a faulted call 
        /// </summary>
        [Browsable(false)]
        public override InArgument<int> RetryCount { get; set; }

        /// <summary>
        /// Get or Set the delay between each retry
        /// </summary>
        [Browsable(false)]
        public override InArgument<TimeSpan> RetryDelay { get; set; }

        /// <summary>
        /// Get or Set the list of Headers thant will be send for each request
        /// </summary>
        [Browsable(false)]
        public override InArgument<List<AddressHeader>> Headers { get; set; }

        /// <summary>
        /// Get or Set the list of EndPoints Behavior that will be activated
        /// </summary>
        [Browsable(false)]
        public override InArgument<List<IEndpointBehavior>> EndPointBehaviors { get; set; }

        #endregion

        #region Activity Arguments

        /// <summary>
        /// Gets or sets if access is in ssl
        /// </summary>
        /// <value>
        /// Use SSL.
        /// </value>
        [Browsable(true)]
        [Category("Authentication")]
        [Description("Set if access is in ssl")]
        public bool UseSsl { get; set; }

        /// <summary>
        /// Gets or sets the consumer key.
        /// <remarks>
        /// Required Argument
        /// </remarks>
        /// </summary>
        /// <value>
        /// The consumer key.
        /// </value>
        [Browsable(true)]
        [RequiredArgument]
        [Category("Authentication")]
        [Description("Set the consumer key")]
        public InArgument<string> ConsumerKey { get; set; }

        /// <summary>
        /// Gets or sets the consumer secret.
        /// <remarks>
        /// Required Argument
        /// </remarks>
        /// </summary>
        /// <value>
        /// The consumer secret.
        /// </value>
        [Browsable(true)]
        [RequiredArgument]
        [Category("Authentication")]
        [Description("Set the consumer secret")]
        public InArgument<string> ConsumerSecret { get; set; }

        /// <summary>
        /// Gets or sets the application access token.
        /// <remarks>
        /// Required Argument
        /// </remarks>
        /// </summary>
        /// <value>
        /// The application access token.
        /// </value>
        [Browsable(true)]
        [RequiredArgument]
        [Category("Authentication")]
        [Description("Set the access token")]
        public InArgument<string> ApplicationAccessToken { get; set; }

        /// <summary>
        /// Gets or sets the application access token secret.
        /// <remarks>
        /// Required Argument
        /// </remarks>
        /// </summary>
        /// <value>
        /// The access application token secret.
        /// </value>
        [Browsable(true)]
        [RequiredArgument]
        [Category("Authentication")]
        [Description("Set the access token secret")]
        public InArgument<string> ApplicationAccessTokenSecret { get; set; }

        /// <summary>
        /// When EnableRateLimitAutoRetry is enabled, the proxy retry to invoke the method if a RateLimitException has been  throw
        /// </summary>
        /// <value>
        /// <c>true</c> if [enable rate limit auto retry]; otherwise, <c>false</c>.
        /// </value>
        [Browsable(true)]
        [Category("RateLimit")]
        [Description("The proxy retry to invoke the method if a RateLimitException has been  throw")]
        public bool EnableRateLimitAutoRetry { get; set; }

        /// <summary>
        /// Delay between a retry
        /// </summary>
        /// <value>
        /// The rate limit auto retry delay.
        /// </value>
        [Browsable(true)]
        [RequiredArgument]
        [Category("RateLimit")]
        [Description("Delay between a retry")]
        public InArgument<TimeSpan> RateLimitAutoRetryDelay { get; set; }

        #endregion


        /// <summary>
        /// Gets the service endpoint.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        protected override System.ServiceModel.Description.ServiceEndpoint GetServiceEndpoint(NativeActivityContext context)
        {
            TwitterExtension extension = context.GetExtension<TwitterExtension>();
            ServiceEndpoint endPoint = TwitterClient.GetTwitterEndpoint(UseSsl, extension.Tokens);
            return endPoint;
        }

        /// <summary>
        /// Caches the metadata.
        /// </summary>
        /// <param name="metadata">The metadata.</param>
        protected override void CacheMetadata(NativeActivityMetadata metadata)
        {
            NotContainConstraint<TwitterProxy> noProxyConstraint =
                    new NotContainConstraint<TwitterProxy>(false, "Proxy", typeof(TwitterProxy));
            this.Constraints.Add(noProxyConstraint.GetConstraint());

            metadata.AddDefaultExtensionProvider<TwitterExtension>(() => new TwitterExtension());

            base.CacheMetadata(metadata);
        }

        /// <summary>
        /// Runs the activity’s execution logic.
        /// </summary>
        /// <param name="context">The execution context in which the activity executes</param>
        protected override void Execute(NativeActivityContext context)
        {
            ChannelType = ChannelType.Web;
            EnablePersistence = true;
            RetryCount.Set(context, 1);
            RetryDelay.Set(context, new TimeSpan(0, 0, 5));

            TwitterExtension extension = context.GetExtension<TwitterExtension>();
            extension.Tokens = new OAuthTokens()
                {
                    ConsumerKey = ConsumerKey.Get(context),
                    ConsumerSecret = ConsumerSecret.Get(context),
                    ApplicationAccessToken = ApplicationAccessToken.Get(context),
                    ApplicationAccessTokenSecret = ApplicationAccessTokenSecret.Get(context)
                };
            extension.EnableRateLimitAutoRetry = EnableRateLimitAutoRetry;
            extension.RateLimitAutoRetryDelay = RateLimitAutoRetryDelay.Get(context);

            base.Execute(context);
        }
    }
}
